﻿using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using Lynn.Infastructure.Extension;
using Lynn.Infastructure.Repository.BaseEntity;
using System;
using Microsoft.Extensions.DependencyInjection;
using System.Text;
using System.Collections.Generic;
using System.Linq;

namespace Lynn.Infastructure.Repository.EFCore
{
    [AppIgnore]
    public class EFCoreBaseConfig<TEntity> : IEntityTypeConfiguration<TEntity> where TEntity : class
    {
        public void Configure(EntityTypeBuilder<TEntity> builder)
        {
            var entity = typeof(TEntity);
            if (typeof(IRowVersion).IsAssignableFrom(entity))
            {
                builder.Property(x => (x as IRowVersion).RowVersion).IsConcurrencyToken();
            }
            if (typeof(IDel).IsAssignableFrom(entity))
            {
                builder.HasQueryFilter(x => (x as IDel).Del == false);
            }
            var tps = entity.GetProperties();
            var attrs=GetColAttributeByInterface(entity);
            foreach (var item in tps)
            {
                var attr = item.GetAttribute<LengthAttribute>();
                if (attr == null)
                {
                    if (!attrs.TryGetValue(item.Name, out attr)) continue;
                }
                var itemName = item.PropertyType.FullName;
                if (item.PropertyType.IsGenericType && item.PropertyType.GetGenericTypeDefinition() == typeof(Nullable<>))
                {
                    itemName = item.PropertyType.GetGenericArguments()[0].FullName;
                }
                itemName = itemName.Replace("System.", "").ToLower();
                if (item.PropertyType.IsEnum || itemName == "int32")
                {
                    itemName = "int";
                }
                if (itemName == "int64")
                {
                    itemName = "long";
                }
                var columnType = ColumnTypeBuild(itemName, attr);
                if (!string.IsNullOrWhiteSpace(columnType))
                {
                    builder.Property(item.Name).HasColumnType(columnType).HasComment(attr.Comment);
                }
                else {
                    builder.Property(item.Name).HasComment(attr.Comment);
                }
            }
            this.Config(builder);
        }
        public virtual void Config(EntityTypeBuilder<TEntity> builder) { }
        /// <summary>
        /// 字段属性
        /// </summary>
        /// <param name="type"></param>
        /// <param name="column"></param>
        /// <returns></returns>
        private string ColumnTypeBuild(string type, LengthAttribute column)
        {
            if (column.Precision == 0) {
                return null;
            }
            var sc = column.Scal > 0 ? $"({column.Precision},{column.Scal})" : $"({column.Precision})";
            var name = "";
            var columnType = "";
            switch (type)
            {
                case "string":
                    name = "varchar";
                    columnType = $"{name}{sc}  CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci";
                    break;
                default:
                    name = type.ToLower();
                    columnType = $"{name}{sc}";
                    break;
            }
            return columnType;
        }
        private Dictionary<string, LengthAttribute> GetColAttributeByInterface(Type type) {
            var dic = new Dictionary<string, LengthAttribute>();
            var interfaces = type.GetInterfaces();
            foreach (var item in interfaces) {
                var ps = item.GetProperties();
                foreach (var propertyType in ps) {
                    var attr = propertyType.GetAttribute<LengthAttribute>();
                    if (attr == null) continue;
                    dic.Add(propertyType.Name, attr);
                }
            }
            return dic;
        }
    }
}
